﻿#region Using Statements
using System;
using System.Reflection;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web;
using System.Web.SessionState;
using System.Web.Services;
using System.Web.Caching;
using System.IO;
using System.Globalization;
using NAudio;
using NAudio.Wave;

#endregion

namespace LM.CaptchaControl
{
    /// <summary>
    /// Summary description for CaptchaImageService
    /// Reloading or palying captcha sound
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    [System.Web.Script.Services.ScriptService]
    public class CaptchaImageService : IHttpHandler, IRequiresSessionState
    {
        #region Public
        public void ProcessRequest(HttpContext context)
        {
            string mypath = context.Request.Path;
            string mypathmethod = context.Request.PathInfo;
            mypathmethod = mypathmethod.Replace(mypath, "");
            if (mypathmethod.StartsWith("/"))
            {
                mypathmethod = mypathmethod.Substring(1);
            }
            else if (mypathmethod.EndsWith("/"))
            {
                mypathmethod = mypathmethod.Substring(0, mypathmethod.Length - 2);
            }
            string[] webmethods = mypathmethod.Split('/');
            if (webmethods.Length != 2)
            {
                context.Response.Write("");
            }
            switch (webmethods[0].ToLower())
            {
                case ("refreshcaptcha"):
                    context.Response.Write(RefreshCaptcha(webmethods[1]));
                    break;
                case ("audiofile"):
                    AudioFile(webmethods[1]);
                    //context.Response.Write(AudioFile(webmethods[1]));
                    break;
                default:
                    //check if guid
                    Guid id;
                    if (Guid.TryParse(webmethods[0].ToLower(), out id))
                    {
                        GetImage(context, id.ToString());
                    }
                    break;
            }
        }

        public bool IsReusable
        {
            get { return true; }
        }
        #endregion

        #region Private
        private int CaptchaMaxTimeout = 90;
        private string RefreshCaptcha(string UniqueID)
        {
            //create new captcha
            CaptchaImage newcaptcha = new CaptchaImage();
            CaptchaImage oldcaptcha = null;
            if (HttpContext.Current.Cache[UniqueID] != null)
            {
                oldcaptcha = (CaptchaImage)HttpContext.Current.Cache[UniqueID];
                HttpContext.Current.Cache.Add(newcaptcha.UniqueId, newcaptcha, null,
                              DateTime.Now.AddSeconds(
                                  Convert.ToDouble((CaptchaMaxTimeout == 0
                                                        ? 90
                                                        : CaptchaMaxTimeout))), TimeSpan.Zero,
                              CacheItemPriority.NotRemovable, null);
            }
            else if (HttpContext.Current.Session[UniqueID] != null)
            {
                oldcaptcha = (CaptchaImage)HttpContext.Current.Session[UniqueID];
                HttpContext.Current.Session.Add(newcaptcha.UniqueId, newcaptcha);
            }
            else
            {
                HttpContext.Current.Session.Add(newcaptcha.UniqueId, newcaptcha);
            }
            if (oldcaptcha != null)
            {
                newcaptcha.CaptchaLanguage = oldcaptcha.CaptchaLanguage;
                newcaptcha.CaptchaColor = oldcaptcha.CaptchaColor;
            }
            return newcaptcha.UniqueId;
        }

        private string AudioFile(string UniqueID)
        {
            CaptchaImage oldcaptcha = null;

            string sFileName = UniqueID + ".mp3";
            if (HttpContext.Current.Cache[UniqueID] != null)
            {
                oldcaptcha = (CaptchaImage)HttpContext.Current.Cache[UniqueID];
            }
            else if (HttpContext.Current.Session[UniqueID] != null)
            {
                oldcaptcha = (CaptchaImage)HttpContext.Current.Session[UniqueID];
            }
            if (oldcaptcha == null)
            {
                return string.Empty;
            }
            //create combined file
            string sText = oldcaptcha.Text;
            string[] inputFiles = new string[sText.Length];
            for (int i = 0; i < sText.Length; i++)
            {
                inputFiles[i] = sText.Substring(i, 1) + ".mp3";
            }
            //using (var fileStream = File.Create(@"C:\Users\Mihail\Desktop\Captcha\Main\Source\Captcha\CaptchaDemoWebsite\App_Data\" + sFileName))
            //{
            //    MergeFiles(inputFiles, fileStream);
            //}

            using (var memstream = new MemoryStream())
            {
                MergeFiles(inputFiles, memstream, oldcaptcha.CaptchaLanguage);
                HttpContext.Current.Response.ContentType = "audio/mpeg";
                HttpContext.Current.Response.ExpiresAbsolute = System.DateTime.MinValue;
                if (memstream != null)
                {
                    byte[] myarray = memstream.GetBuffer();
                    HttpContext.Current.Response.OutputStream.Write(myarray, 0, Convert.ToInt32(memstream.Length));
                }
                memstream.Close();

                //HttpContext.Current.Response.BinaryWrite(file.Data);
                HttpContext.Current.Response.Flush();

                //HttpContext.Current.Response.End();
            }
            return sFileName;
        }

        private void GetImage(HttpContext context, string guid)
        {
            CaptchaImage ci = null;
            HttpApplication app = context.ApplicationInstance;

            //if (app.Request.QueryString["guid"] == null)
            //{
            //    app.Response.StatusCode = 404;
            //    app.CompleteRequest();
            //}
            //string guid = app.Request.QueryString["guid"];

            string s = String.Empty;
            if (app.Request.QueryString["s"] != null)
            {
                s = app.Request.QueryString["s"];
            }

            if (!String.IsNullOrEmpty(guid))
            {
                if (String.IsNullOrEmpty(s))
                {
                    ci = (CaptchaImage)context.Cache[guid];
                }
                else
                {
                    ci = (CaptchaImage)context.Session[guid];
                }
            }

            if (ci == null)
            {
                app.Response.StatusCode = 404;
                app.CompleteRequest();
            }
            else
            {
                Bitmap b = ci.RenderImage();
                b.Save(app.Context.Response.OutputStream, ImageFormat.Jpeg);
                b.Dispose();
                app.Response.ContentType = "image/jpg";
                app.Response.StatusCode = 200;
                app.CompleteRequest();
            }
        }
        public void MergeFiles(string[] inputFiles, MemoryStream output, CultureInfo CaptachCulture)
        {
            string sResourceSounds = "LM.sounds." + CaptachCulture.ToString().ToLower().Replace("-", "_");// "en_us";

            foreach (string file in inputFiles)
            {
                Stream sInput = Assembly.GetExecutingAssembly().GetManifestResourceStream(sResourceSounds + "." + file.ToLower());
                using (Mp3FileReader reader = new Mp3FileReader(sInput, new Mp3FileReader.FrameDecompressorBuilder(wave => new NLayer.NAudioSupport.Mp3FrameDecompressor(wave))))
                {
                    if ((output.Position == 0) && (reader.Id3v2Tag != null))
                    {
                        output.Write(reader.Id3v2Tag.RawData, 0, reader.Id3v2Tag.RawData.Length);
                    }
                    Mp3Frame frame;
                    while ((frame = reader.ReadNextFrame()) != null)
                    {
                        output.Write(frame.RawData, 0, frame.RawData.Length);
                    }
                }
            }
        }
        #endregion
    }
}